package com.lb.dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.lb.dao.redis.*;
import lombok.AllArgsConstructor;
import org.apache.ibatis.reflection.MetaObject;
import org.mybatis.spring.annotation.MapperScan;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.redisson.spring.data.connection.RedissonConnectionFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.config.EnableMongoAuditing;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.LocalDateTime;
import java.util.List;

/**
 * 持久层配置类
 *
 * @author libin
 * @since 1.0
 */
@Configuration
@ComponentScan({"com.lb.dao"})
public class DaoConfiguration {

    @Configuration
    @EnableMongoAuditing
    @ConditionalOnClass(MongoTemplate.class)
    @EnableMongoRepositories(basePackages = {"com.lb.dao.mongo"})
    public static class MongoConfiguration {

    }

    @Configuration
    @ConditionalOnClass(RedisTemplate.class)
    @AllArgsConstructor
    @EnableConfigurationProperties(CustomRedisProperties.class)
    public static class RedisTemplateConfiguration {
        private static final String REDIS_PROTOCOL_PREFIX = "redis://";
        private final RedisProperties redisProperties;
        private final CustomRedisProperties customRedisProperties;

        @Bean
        public RedisTemplate<String, Object> jsonRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new FastJsonRedisSerializer<>(JSON.class));
            redisTemplate.setHashValueSerializer(new FastJsonRedisSerializer<>(JSON.class));
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            return redisTemplate;
        }

        @Bean
        public RedisTemplate<String, Integer> integerRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
            RedisTemplate<String, Integer> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new IntegerRedisSerializer());
            redisTemplate.setConnectionFactory(redisConnectionFactory);
            return redisTemplate;
        }

        @Bean(name = "delayRedisTemplate")
        public RedisTemplate<String, String> delayRedisTemplate() {
            RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
            redisTemplate.setKeySerializer(new StringRedisSerializer());
            redisTemplate.setHashKeySerializer(new StringRedisSerializer());
            redisTemplate.setValueSerializer(new StringRedisSerializer());
            redisTemplate.setHashValueSerializer(new StringRedisSerializer());
            redisTemplate.setConnectionFactory(createFactory());
            return redisTemplate;
        }

        public RedissonConnectionFactory createFactory() {
            //工厂创建
            Config config = new Config();
            config.useSingleServer().setAddress(REDIS_PROTOCOL_PREFIX + redisProperties.getHost() + ":" + redisProperties.getPort()).setDatabase(customRedisProperties.getSecondDatabase()).setPassword(redisProperties.getPassword());
            RedissonClient client = Redisson.create(config);
            return new RedissonConnectionFactory(client);
        }


        @Bean
        public RedisKeyExpirationEventMessageDatabaseListener keyExpirationEventMessageListener(RedisMessageListenerContainer container) {
            return new RedisKeyExpirationEventMessageDatabaseListener(container, customRedisProperties.getSecondDatabase());
        }
    }

    @Configuration
    @AllArgsConstructor
    @ConditionalOnClass(RedisTemplate.class)
    public static class RedisConfiguration {


        private final StringRedisTemplate stringRedisTemplate;
        private final List<RedisKeyExpiredListener> listeners;

        @Bean
        public RedisMessageListenerContainer redisMessageListenerContainer(RedisConnectionFactory redisConnectionFactory) {
            RedisMessageListenerContainer container = new RedisMessageListenerContainer();
            container.setConnectionFactory(redisConnectionFactory);
            return container;
        }


        @Bean
        public <T> RedisKeyExpiredEventDispatcher<T> redisKeyExpiredDispatcher() {
            return new RedisKeyExpiredEventDispatcher<>(stringRedisTemplate, listeners);
        }
    }

    @Configuration
    @MapperScan("com.lb.dao.mysql")
    public static class MyBatisPlusConfiguration {

        @Bean
        public MybatisPlusInterceptor mybatisPlusInterceptor() {
            MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
            return interceptor;
        }

        @Bean
        public MetaObjectHandler metaObjectHandler() {
            return new MetaObjectHandler() {
                @Override
                public void insertFill(MetaObject metaObject) {
                    this.setFieldValByName("createTime", LocalDateTime.now(), metaObject);
                    this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
                }

                @Override
                public void updateFill(MetaObject metaObject) {
                    this.setFieldValByName("updateTime", LocalDateTime.now(), metaObject);
                }
            };
        }
    }

    public static void main(String[] args) {
        for (String s : "1_9_冰镇西瓜头像框_20_219_1_0_20天".split("_")) {
            System.out.println(s);
        }
    }
}